package data

import (
	"database/sql"
	"fmt"
	"time"

	"github.com/astaxie/beego/orm"
	_ "github.com/go-sql-driver/mysql"
)

type Trans struct {
	o orm.Ormer
}

func GetCategoryList() (list []Category, err error) {
	o := orm.NewOrm()
	_, err = o.QueryTable(new(Category)).OrderBy("sort_order").All(&list)
	return
}

func GetAttributeList() (list []Attribute, err error) {
	o := orm.NewOrm()
	_, err = o.QueryTable(new(Attribute)).OrderBy("cat_id", "sort_order").All(&list)
	return
}

func GetAttributeListByCategoryID(categoryID int64) (list []Attribute, err error) {
	o := orm.NewOrm()
	_, err = o.QueryTable(new(Attribute)).
		Filter("CategoryID", categoryID).
		OrderBy("sort_order").All(&list)
	return
}

func GetGoodsList(categoryID int64, pageNo, pageSize int) (totalCount int64, list []Goods, err error) {
	query := orm.NewOrm().QueryTable(new(Goods))
	if categoryID != -1 {
		query = query.Filter("CategoryID", categoryID)
	}
	if _, err = query.
		Filter("IsOnSale", 1).
		Filter("IsDelete", 0).
		Filter("IsCheck", 1).
		OrderBy("sort_order").
		Limit(pageSize, (pageNo-1)*pageSize).
		All(&list); err == nil {
		totalCount, err = query.
			Filter("IsOnSale", 1).
			Filter("IsDelete", 0).
			Filter("IsCheck", 1).Count()
	}
	return
}

func GetGoodsByID(goodsID int64) (goods Goods, err error) {
	o := orm.NewOrm()
	err = o.QueryTable(new(Goods)).
		Filter("ID", goodsID).
		Filter("IsOnSale", 1).
		Filter("IsDelete", 0).
		Filter("IsCheck", 1).
		One(&goods)
	return
}

func GetGoodsAttrsByGoodsID(goodsID int64) (list []GoodsAttribute, err error) {
	o := orm.NewOrm()
	_, err = o.Raw(SQL_GET_GOODS_ATTR, goodsID).QueryRows(&list)
	return
}

func UpdateGoodsImage(goodsID int64, thumb, large, original string) error {
	o := orm.NewOrm()
	_, err := o.Raw(SQL_UPDATE_GOODS_IMG, thumb, large, original, goodsID).Exec()
	return err
}

func BeginTx() (trans *Trans, err error) {
	trans = &Trans{o: orm.NewOrm()}
	if err = trans.o.Begin(); err != nil {
		trans.o.Rollback()
	}
	return
}

func (trans *Trans) End(ok bool) (err error) {
	if ok {
		err = trans.o.Commit()
	} else {
		err = trans.o.Rollback()
	}
	return
}

func (tx *Trans) CreateOrder(goods *OrderGoods, order *Order) (no string, err error) {
	var id int64
	if id, err = tx.o.Insert(order); err == nil {
		order.ID = id
		order.NO = fmt.Sprintf("%s%010d", time.Now().Format("060102150405"), id)
		if _, err = tx.o.Update(order, "NO"); err == nil {
			goods.OrderID = id
			_, err = tx.o.Insert(goods)
		}
	}
	return order.NO, nil
}

func GetOrderByNO(orderNO, memberID string) (order Order, err error) {
	o := orm.NewOrm()
	err = o.QueryTable(new(Order)).
		Filter("UserID", memberID).
		Filter("NO", orderNO).
		One(&order)
	return
}

func GetOrderGoodsByID(orderID int64) (goods OrderGoods, err error) {
	o := orm.NewOrm()
	err = o.QueryTable(new(OrderGoods)).
		Filter("OrderID", orderID).
		One(&goods)
	return
}

func GetOrderList(memberID string, pageNo, pageSize int) (list []OrderInfo, totalCount int64, err error) {
	o := orm.NewOrm()
	if totalCount, err = o.QueryTable(new(Order)).Filter("UserID", memberID).Count(); err == nil {
		_, err = o.Raw(SQL_GET_ORDER_LIST, memberID, (pageNo-1)*pageSize, pageSize).QueryRows(&list)
	}
	return
}

func GetLastOrder(memberID string) (order Order, err error) {
	o := orm.NewOrm()
	err = o.QueryTable(new(Order)).
		Filter("UserID", memberID).
		Filter("PayStatus", 1).
		OrderBy("-order_id").
		One(&order)
	return
}

func PrepareToCharge(memberID int, goodsID int64, goodsNumber, amount int) (ok bool, err error) {
	var count int64
	var result sql.Result
	if count, err = orm.NewOrm().QueryTable(new(Goods)).
		Filter("ID", goodsID).
		Filter("goods_number__gte", goodsNumber).Count(); count > 0 {
		o := orm.NewOrm()
		o.Using("kly")
		if result, err = o.Raw(SQL_REDUCE_USER_POINT, amount, amount, memberID).Exec(); err == nil {
			if count, err = result.RowsAffected(); count > 0 {
				ok = true
			}
		}
	}
	return
}

func (tx *Trans) Charge(memberID string, order Order, goods OrderGoods) error {
	var err error
	var result sql.Result
	var affectedCount int64

	stmt := tx.o.Raw(SQL_REDUCE_GOODS_AMOUNT, goods.Number, goods.Number, goods.ID)
	if result, err = stmt.Exec(); err == nil {
		if affectedCount, err = result.RowsAffected(); affectedCount == 1 {
			if _, err = tx.o.Insert(&PayLog{
				OrderID: order.ID,
				Amount:  order.PayFee,
				IsPaid:  1,
			}); err == nil {
				_, err = tx.o.Raw(SQL_FINISH_ORDER,
					1,
					1,
					time.Now().Format("20060102150405"),
					time.Now().Format("20060102150405"),
					order.ID).Exec()
			}
		} else {
			err = fmt.Errorf("affectcount:%d", affectedCount)
		}
	}

	return err
}
